-- SkyShipSkillM
-- created by panyl
-- 空战秘宝模块

module("SkyShipSkillM", package.seeall);

local shipSkills = {};

local rules = {};

-- 载入配置表
local _init = false;
local loadCsv = function()
    if _init then return end
    _init = true;

    shipSkills = {};

    -- 转换下sky_explore_event_CSV信息表
    local airship_skill_CSV = get_airship_skill_CSV();
    for i = 1, #airship_skill_CSV do
        local row = airship_skill_CSV[i];
        shipSkills[row.id] = row;

        row.apply = string.explode(row.apply, "+");
    end
end

-- 模块初始化操作
function init()
    if not _init then
        loadCsv();

        -- 载入所有的规则处理子模块
        rules = LOAD_PATH("game/logic/module/airship_skills");
    end

    EventMgr.removeAll("SkyShipSkillM");
end

function query(id, path)
    local m = shipSkills[id];

    if not m or not path then
        return m;
    end

    return m[path];
end

-- 获取所有的冈布奥秘宝
function getAllShipSkills()
    local ret = {};
    for _, info in pairs(shipSkills) do
        if type(info["group"]) == "table" and #info["group"] > 0 then
            table.insert(ret, info);
        end
    end
    return ret;
end

-- 是否已经拥有了秘宝
function hasOwn(id)
    return getProgress(id) >= query(id, "progress");
end

-- 增加激活进度
function addProgress(id, add)
    local shipSkills = ME.user.dbase:query("shipSkills", {});

    shipSkills[id] = (shipSkills[id] or 0) + add;

    ME.user.dbase:set("shipSkills", shipSkills);
end

-- 获取当前进度
function getProgress(id)
    local shipSkills = ME.user.dbase:query("shipSkills", {});

    return shipSkills[id] or 0;
end

-- 释放技能
function apply(source, target, id, round, value)
    value = value or {};

    -- 1. 发挥作用
    local result = { ["damage"] = 0, ["cure"] = 0, };
    local args = query(id, "apply");
    for index = 1, #args do

        if #args[index] <= 0 then
            assert(false, "应该是配置错误！");
            break;
        end

        local _, __, rule, para = string.find(args[index], "([^%(]+)%((.*)%)$");
        local f = rules[rule];

        -- 解析下参数规则
        local para = f.parse(para);

        -- 发挥作用
        local ret = f.apply(source, target, id, round, para, value[index]);

        if type(ret) == "table" then
            result["damage"] = result["damage"] + ret["damage"] or 0;
            result["cure"] = result["cure"] + ret["cure"] or 0;
        end
    end

    return result;
end

-- 获取玩家所有已经获得的秘宝信息
function getShipSkillsInfo()
    local ret = {};
    for _, info in pairs(shipSkills) do
        if hasOwn(info.id) then
            table.insert(ret, info);
        end
    end
    return ret;
end

-- 获取玩家已经拥有的某分类的秘宝组合
function getShipSkillsInfoByClass(skillClass)
    local ret = {};
    for _, info in pairs(shipSkills) do
        if info.class == skillClass and hasOwn(info.id) then
            table.insert(ret, info);
        end
    end
    return ret;
end

-- 获取某只宠物的所有秘宝信息(玩家已经拥有的秘宝)
function getShipSkillsByPetId(classId)
    local ret = {};
    for _, info in pairs(getShipSkillsInfo()) do
        if table.indexOf(info.group, classId) ~= -1 then
            table.insert(ret, info);
        end
    end
    return ret;
end

-- 获取某只宠物的所有秘宝信息(所有秘宝无论玩家是否获得)
function getAllShipSkillsByPetId(classId)
    local ret = {};
    for _, info in pairs(shipSkills) do
        if table.indexOf(info.group, classId) ~= -1 then
            table.insert(ret, info);
        end
    end
    return ret;
end

-- 获取当前已经激活的所有秘宝
-- @param petList 用于计算当前已激活的所有秘宝的冈布奥列表，如果没有传入，则默认使用当前出战的冈布奥列表
function getActivityShipSkills(petList)
    local ret = {};
    for _, info in pairs(getShipSkillsInfo()) do
        local group = info.group;
        local activity = true;
        for _, id in pairs(group) do
            if petList then
                if table.indexOf(petList, id) < 0 then
                    activity = false;
                    break;
                end
            else
                if not SkyCombatM.isInArmy(id) then
                    activity = false;
                    break;
                end
            end
        end

        if activity then
            table.insert(ret, info);
        end
    end
    return ret;
end

-- 判断指定秘宝是否激活
-- @param petList 用于判断秘宝是否激活的冈布奥列表，如果没有传入，则默认使用当前出战的冈布奥列表
function isSkillActived(skillId, petList)
    local list = petList or SkyCombatM.getSkyArmy();

    for _, petId in ipairs(query(skillId, "group")) do
        if table.indexOf(list, petId) < 0 then
            return false;
        end
    end

    return true;
end

-- 被动秘宝的四维加成
-- @param petList 用于计算秘宝四维加成的冈布奥列表，如果没有传入，则默认使用当前出战的冈布奥列表
function calcShipAttrib(attrib, baseValue, petList)
    local skills = getActivityShipSkills(petList);

    local addon = 0;
    for _, info in pairs(skills) do
        local skillId = info["id"];

        repeat

            -- 不是被动秘宝
            if query(skillId, "type") ~= SHIP_SKILL_PASSIVE then
                break;
            end

            local args = query(skillId, "apply");

            for index = 1, #args do
                local _, __, rule, para = string.find(args[index], "([^%(]+)%((.*)%)$");
                local f = rules[rule];

                -- 解析下参数规则
                local para = f.parse(para);

                -- 计算加成
                addon = addon + f.calcAddon(attrib, baseValue, para);
            end
        until true;
    end

    return baseValue + addon;
end

-- 计算某个舰队的四维加成
function calcAddon(ship, attrib, baseValue)
    local skills = ship:getAllPassive();
    local ret = 0;

    for _, skillId in pairs(skills) do
        local args = query(skillId, "apply");
        for index = 1, #args do
            local _, __, rule, para = string.find(args[index], "([^%(]+)%((.*)%)$");
            local f = rules[rule];

            -- 解析下参数规则
            local para = f.parse(para);

            -- 发挥作用
            if f.calcAddon then
                ret = ret + f.calcAddon(attrib, baseValue, para);
            end
        end
    end

    return ret;
end

-- 计算被动秘宝的四维加成
-- 用于敌方属性计算
function calcPassiveAttrib(attrib, baseValue, shipSkills)
    local addon = 0;
    for _, skillId in pairs(shipSkills) do
        repeat
            -- 不是被动秘宝
            if query(skillId, "type") ~= SHIP_SKILL_PASSIVE then
                break;
            end

            local args = query(skillId, "apply");

            for index = 1, #args do
                local _, __, rule, para = string.find(args[index], "([^%(]+)%((.*)%)$");
                local f = rules[rule];

                -- 解析下参数规则
                local para = f.parse(para);

                -- 计算加成
                addon = addon + f.calcAddon(attrib, baseValue, para);
            end
        until true;
    end

    return baseValue + addon;
end

-- 获取秘宝描述
function getShipSkillDetail(skillId)
    -- 秘宝发动类型描述
    local desc = query(skillId, "detail");

    if desc == "script_desc" then
        -- 如果有skyProp的描述，放在最前面
        local prop = query(skillId, "prop");
        local propDesc;
        if #table.keys(prop) > 0 then
            propDesc = SkyPropM.getDesc(prop);
        end

        if propDesc then
            desc = propDesc .. "\n";
        else
            desc = "";
        end

        -- 根据子规则的效果拼接描述
        local triggerType = query(skillId, "type");
        local rate = query(skillId, "rate")

        -- 如果是触发类秘宝
        if triggerType == SHIP_SKILL_REPLACE or
            triggerType == SHIP_SKILL_HIT or
            triggerType == SHIP_SKILL_ATTACK then
            desc = desc .. string.format(getLocStr("shipskill_type_desc_" .. triggerType), rate) .. "\n";
        end

        local args = query(skillId, "apply");
        local count = #args;
        for index = 1, count do
            local _, __, rule, para = string.find(args[index], "([^%(]+)%((.*)%)$");
            local f = rules[rule];

            -- 取子规则的描述，用"，"隔开
            para = f.parse(para);

            desc = desc .. f.getDetail(para) .. "\n";
        end

    elseif desc == "script_shipgun_desc" then
        -- 飞船主炮描述
        desc = "";
        --local rate = query(skillId, "rate");
        local args = query(skillId, "apply");

        local count = #args;
        for index = 1, count do
            local _, __, rule, para = string.find(args[index], "([^%(]+)%((.*)%)$");
            local f = rules[rule];

            -- 取子规则的描述，不同子规则需要换行
            para = f.parse(para);
            --if rule == "physic" or rule == "damage_debuff" then
            --    desc = desc .. f.getShipgunDetail(para, rate);
            if rule == "physics_attack" then
                desc = desc .. f.getShipgunDetail(para);
            else
                desc = desc .. f.getDetail(para);
            end

            if index ~= count then
                desc = desc .. getLocStr("comma") .. "\n";
            end
        end
    end

    return desc;
end

-- 获取秘宝的效果描述
function getShipSkillDesc(skillId)
    local desc = query(skillId, "desc");
    local pre  = "script_";

    if string.startWith(desc, pre) == true then
        -- 使用通用描述
        local name = string.sub(desc, string.len(pre) + 1);
        return getLocStr(name);
    else
        return desc;
    end
end

-- 根据技能等级获取技能ID
function getSkillByLevel(skillId, level)
    -- TODO： 直接加上等级
    if not shipSkills[skillId] or not shipSkills[skillId + level] then
        return skillId;
    end

    return skillId + level;
end

-- 解析描述
function parseDesc(skillId, desc)
    -- 优先使用传入的描述，否则取技能描述
    if type(desc) ~= 'string' then
        desc = query(skillId, "desc");
    end

    -- 先解析子规则的描述
    local args = query(skillId, "apply");
    local count = #args;
    for index = 1, count do
        local _, __, rule, para = string.find(args[index], "([^%(]+)%((.*)%)$");
        local f = rules[rule];
        para = f.parse(para);

        if f.parseDesc then
            desc = f.parseDesc(desc, para);
        end
    end

    -- 再解析天空属性的描述
    local prop = query(skillId, "prop");
    desc = SkyPropM.parseDesc(desc, prop);

    return desc;
end